<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图片懒加载示例 - elementIsVisibleInViewport</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
            background-color: #f5f5f5;
            color: #333;
            line-height: 1.6;
        }

        header {
            background-color: #2396ef;
            color: white;
            padding: 20px;
            text-align: center;
            position: sticky;
            top: 0;
            z-index: 100;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }

        .intro {
            background-color: white;
            padding: 20px;
            border-radius: 8px;
            margin-bottom: 20px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
        }

        .intro-list {
            margin: 15px 0;
            padding-left: 20px;
            list-style: none;
        }

        .intro-list li {
            margin-bottom: 10px;
            position: relative;
            padding-left: 15px;
        }

        .intro-list li:before {
            content: '';
            position: absolute;
            left: 0;
            top: 8px;
            width: 6px;
            height: 6px;
            background-color: #2396ef;
            border-radius: 50%;
        }

        .intro-list li:hover {
            color: #2396ef;
            transform: translateX(5px);
            transition: all 0.3s ease;
        }

        .gallery {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
            gap: 20px;
        }

        .image-card {
            background-color: white;
            border-radius: 8px;
            overflow: hidden;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
            transition: transform 0.3s ease;
        }

        .image-card:hover {
            transform: translateY(-5px);
        }

        .image-container {
            height: 250px;
            background-color: #eee;
            display: flex;
            align-items: center;
            justify-content: center;
            position: relative;
        }

        .lazy-image {
            width: 100%;
            height: 100%;
            object-fit: cover;
            opacity: 0;
            transition: opacity 0.5s ease;
        }

        .lazy-image.loaded {
            opacity: 1;
        }

        .placeholder {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: #999;
            font-size: 14px;
            text-align: center;
        }

        .loading-spinner {
            width: 40px;
            height: 40px;
            border: 4px solid rgba(35, 150, 239, 0.2);
            border-radius: 50%;
            border-top-color: #2396ef;
            animation: spin 1s linear infinite;
            margin: 0 auto 10px;
        }

        @keyframes spin {
            to {
                transform: rotate(360deg);
            }
        }

        .image-info {
            padding: 15px;
        }

        .image-title {
            font-size: 18px;
            margin-bottom: 8px;
            color: #333;
        }

        .image-description {
            font-size: 14px;
            color: #666;
        }

        .stats {
            background-color: white;
            padding: 20px;
            border-radius: 8px;
            margin-top: 20px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
        }

        .stats-title {
            font-size: 18px;
            margin-bottom: 10px;
            color: #333;
        }

        .stats-content {
            font-size: 14px;
            color: #666;
        }

        footer {
            text-align: center;
            padding: 20px;
            margin-top: 40px;
            color: #666;
            font-size: 14px;
        }
    </style>
</head>

<body>
    <header>
        <h1>图片懒加载示例</h1>
        <p>基于 elementIsVisibleInViewport 函数实现</p>
    </header>

    <div class="container">
        <div class="intro">
            <h2>关于图片懒加载</h2>
            <p>图片懒加载是一种网页性能优化技术，它延迟加载页面中不可见部分的图片，直到用户滚动到它们附近时才开始加载。这种技术可以：</p>
            <ul class="intro-list">
                <li>减少初始页面加载时间</li>
                <li>节省用户的带宽使用</li>
                <li>提高整体用户体验</li>
                <li>减轻服务器负载</li>
            </ul>
            <p>本示例使用 elementIsVisibleInViewport 函数检测图片元素是否在视口中可见，从而实现懒加载功能。</p>
        </div>

        <div class="gallery" id="image-gallery">
            <!-- 图片卡片将通过JavaScript动态生成 -->
        </div>

        <div class="stats" id="stats-container">
            <h3 class="stats-title">加载统计</h3>
            <div class="stats-content" id="stats-content">
                <p>总图片数: <span id="total-images">0</span></p>
                <p>已加载图片: <span id="loaded-images">0</span></p>
                <p>节省的初始加载请求: <span id="saved-requests">0</span></p>
            </div>
        </div>
    </div>

    <footer>
        <p>elementIsVisibleInViewport 函数实战应用示例 &copy; 2023</p>
    </footer>

    <script>
        // elementIsVisibleInViewport 函数 - 检测元素是否在视口中可见
        const elementIsVisibleInViewport = (el, partiallyVisible = false) => {
            const { top, left, bottom, right } = el.getBoundingClientRect();
            const { innerHeight, innerWidth } = window;
            return partiallyVisible
                ? ((top > 0 && top < innerHeight) ||
                    (bottom > 0 && bottom < innerHeight)) &&
                ((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth))
                : top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth;
        };

        // 模拟图片数据
        const imageData = Array.from({ length: 20 }, (_, index) => ({
            id: index + 1,
            title: `图片 ${index + 1}`,
            description: `这是第 ${index + 1} 张图片的描述，展示了懒加载的效果。`,
            // 使用不同尺寸的占位图片
            url: `https://picsum.photos/id/${(index % 10) + 10}/600/400`
        }));

        // 统计数据
        const stats = {
            totalImages: imageData.length,
            loadedImages: 0,
            savedRequests: imageData.length // 初始时所有图片都未加载
        };

        // 更新统计信息
        function updateStats() {
            document.getElementById('total-images').textContent = stats.totalImages;
            document.getElementById('loaded-images').textContent = stats.loadedImages;
            document.getElementById('saved-requests').textContent = stats.savedRequests;
        }

        // 创建图片卡片
        function createImageCards() {
            const gallery = document.getElementById('image-gallery');

            imageData.forEach(image => {
                const card = document.createElement('div');
                card.className = 'image-card';

                const imageContainer = document.createElement('div');
                imageContainer.className = 'image-container';

                // 创建占位符
                const placeholder = document.createElement('div');
                placeholder.className = 'placeholder';
                placeholder.innerHTML = `
                    <div class="loading-spinner"></div>
                    <p>图片加载中...</p>
                `;

                // 创建图片元素，但不设置src
                const img = document.createElement('img');
                img.className = 'lazy-image';
                img.alt = image.title;
                img.dataset.src = image.url; // 将真实URL存储在data属性中

                imageContainer.appendChild(placeholder);
                imageContainer.appendChild(img);

                const imageInfo = document.createElement('div');
                imageInfo.className = 'image-info';
                imageInfo.innerHTML = `
                    <h3 class="image-title">${image.title}</h3>
                    <p class="image-description">${image.description}</p>
                `;

                card.appendChild(imageContainer);
                card.appendChild(imageInfo);
                gallery.appendChild(card);
            });

            // 初始化统计信息
            updateStats();

            // 初始检查哪些图片在视口中
            checkImagesInViewport();
        }

        // 检查哪些图片在视口中并加载它们
        function checkImagesInViewport() {
            const lazyImages = document.querySelectorAll('img.lazy-image:not(.loaded)');

            lazyImages.forEach(img => {
                if (elementIsVisibleInViewport(img, true)) { // 使用partiallyVisible=true
                    loadImage(img);
                }
            });
        }

        // 加载图片
        function loadImage(img) {
            const src = img.dataset.src;
            if (!src) return;

            // 设置加载事件
            img.onload = function () {
                // 图片加载完成后，添加loaded类并移除placeholder
                img.classList.add('loaded');
                const placeholder = img.parentElement.querySelector('.placeholder');
                if (placeholder) {
                    placeholder.style.display = 'none';
                }

                // 更新统计信息
                stats.loadedImages++;
                stats.savedRequests--;
                updateStats();
            };

            // 开始加载图片
            img.src = src;
        }

        // 监听滚动事件
        function setupScrollListener() {
            // 使用防抖函数优化滚动事件
            let scrollTimeout;
            window.addEventListener('scroll', function () {
                if (scrollTimeout) {
                    clearTimeout(scrollTimeout);
                }

                scrollTimeout = setTimeout(function () {
                    checkImagesInViewport();
                }, 100); // 100ms的防抖延迟
            });

            // 监听窗口大小变化
            window.addEventListener('resize', checkImagesInViewport);
        }

        // 初始化
        function init() {
            createImageCards();
            setupScrollListener();

            // 添加一个小提示，告诉用户可以滚动查看更多图片
            console.log('滚动页面查看更多图片，观察懒加载效果！');
        }

        // 页面加载完成后初始化
        document.addEventListener('DOMContentLoaded', init);
    </script>
</body>

</html>